

# 全文查询、词项查询、复合查询、嵌套查询、位置查询、特殊查询


# ---------------------------------全文查询---------------------------------

"""  match query
对查询语句进行分词，分词后查询语句的任何一个词项被匹配，文档就会被搜到，默认情况下相当于对分词后词项进行 or 匹配操作。

GET article/_search
{
  "query": {
    "match": {
      "title": {
        "query": "Elasticsearch 查询优化"
        # ,"operator": "or"  # <--------这里加不加都行默认 就是 or  --------- 如果要同时匹配所有关键词  使用  and
      }
    }
  }
}
"""



"""  match_phrase query
把 query 内容分词，分词器可以自定义
分词后所有词项都要出现在该字段中（相当于 and 操作）。
字段中的词项顺序要一致

PUT test_idx/test_tp/1
{ "desc": "what a wonderful life" }

PUT test_idx/test_tp/2
{ "desc": "what a life"}

PUT test_idx/test_tp/3
{ "desc": "life is what"}

GET test_idx/test_tp/_search
{
  "query": {
    "match_phrase": {
      "desc": "what life"
    }
  }
}



GET /_search
{
  "query": {
    "match_phrase": {
      "field_name": {
        "query": "query string",
        "slop": 2,  <----------------------0 次序保持一致，  2 表示 两个词项交换位置
        "boost": 10.0,    《------------查询权重
        "analyzer": "my_analyzer"   《-----------分词器
      }
    }
  }
}


GET /_search
{
  "query": {
    "match": {
      "field_name": {
        "query": "query string",
        "type": "phrase"
      }
    }
  }
}
"""



"""  match_phrase_prefix
# DSL语句
GET /tehero_index/_doc/_search
{
  "query":{
    "match_phrase":{
      "content.ik_smart_analyzer":"我编程系"
    }
  }
“我”和“编程”是精确匹配，“系”是前缀匹配，等价于sql：【where Token = ‘我’ and 我_Position=0 and Token = ‘编程’ and 编程_Position=1 and (Token_Position=2 and Token like ‘系%’)】
"""


"""  multi_match 是 match 的升级，用于搜索多个字段

GET <index>/_search
{
  "query": {
    "multi_match": {
      "query": "<query keyword>",
      "type": "<multi_match_type>",   ------------指定查询类型
      "fields": [    ---------数组，默认支持最大长度1024
        "<field_a>",
        "<field_b>",
        "*_name",     ----------------支持通配符
        "title^3"   ----------- 关键词出现在 title 中的权重是出现在 description 字段中的 3 倍
      ],
      "tie_breaker" : 0.0   --------------每个字段对应的可控制的权重系数
    }
  }
}


GET books/_search
{
  "query": {
    "multi_match": {
      "query": "java 编程",
      "fields": ["title", "description"]
    }
  }
}
"""



"""
common_terms query 是一种在不牺牲性能的情况下替代停用词提高搜索准确率和召回率的方案

GET books/_search
{
	"query": {
		"common": {
			"body": {
				"query": "nelly the elephant as a cartoon",
				"cutoff_frequency": 0.001,
				"low_freq_operator": "and"
			}
		}
	}
}

        等价操作

GET books/_search
{
	"query": {
		"bool": {
			"must": [
			  { "term": { "body": "nelly" } },
			  { "term": { "body": "elephant" } },
			  { "term": { "body": "cartoon" } }
			],
			"should": [
			  { "term": { "body": "the" } },
			  { "term": { "body": "as" } },
			  { "term": { "body": "a" } }
			]
		}
	}
}



GET /_search
{
    "query": {
        "query_string" : {
            "fields" : ["content", "name"],      -------------  检索 fields  包含  this  和  that 的，支持多字段 
            "query" : "this AND that"
        }
    }
}
"""




"""
simple_query_string 是一种适合直接暴露给用户，并且具有非常完善的查询语法的查询语句
允许用户使用简单的语法构建查询，同时忽略无效的语法部分
类似于query_string ，但是会忽略错误的语法，永远不会引发异常，并且会丢弃查询的无效部分


+ 表示与运算，相当于query_string 的 AND
| 表示或运算，相当于query_string  的 OR
- 取反单个令牌,相当于query_string 的 NOT
"" 表示对检索词进行 match_phrase query
* 字词末尾表示前缀查询

# 1、检索到文档4
GET /tehero_index/_doc/_search
{
    "query": {
        "simple_query_string" : {
            "fields" : ["content.ik_smart_analyzer"],
            "query" : "系统学 + 间隔"
        }
    }
}

GET /tehero_index/_doc/_search
{
    "query": {
        "simple_query_string" : {
            "fields" : ["content.ik_smart_analyzer"],
            "query" : "\"系统学编程关注\""
        }
    }
}
"""


# ---------------------------------词项查询---------------------------------


"""
查询 title 字段中含有关键词 “思想” 的书籍
GET books/_search
{
  "query": {
    "term": {
      "title": "思想"
    }
  }
}

默认情况下，Elasticsearch 针对 text 字段的值进行解析分词，这会使查找 text 字段值的精确匹配变得困难,要搜索 text 字段值，需改用 match 查询。


terms query
想查询 title 字段中包含关键词 “java” 或 “python” 的文档，
{
  "query": {
    "terms": {
      "title": ["java", "python"]
    }
  }
}

"""



"""
range query 即范围查询，

查询价格大于 50，小于等于 70 的书籍，即 50 < price <= 70
GET bookes/_search
{
  "query": {
    "range": {
      "price": {
        "gt": 50,
        "lte": 70
      }
    }
  }
}

查询出版日期在 2015 年 1 月 1 日和 2019 年 12 月 31 之间的书籍，对 publish_time 字段进行范围查询
{
  "query": {
    "range": {
      "publish_ time": {
        "gte": "2015-01-01",
        "lte": "2019-12-31",
        "format": "yyyy-MM-dd"
      }
    }
  }
}
"""






"""
            exists 查询会返回字段中至少有一个非空值的文档
{
  "query": {
    "exists": {
      "field": "user"
    }
  }
}
-------------会匹配------------------
{ "user" : "jane" } 有 user 字段，且不为空。
{ "user" : "" } 有 user 字段，值为空字符串。
{ "user" : "-" } 有 user 字段，值不为空。
{ "user" : [ "jane" ] } 有 user 字段，值不为空。
{ "user" : [ "jane", null ] } 有 user 字段，至少一个值不为空即可。
--------------不会被匹配----------------
{ "user" : null } 虽然有 user 字段，但是值为空。
{ "user" : [] } 虽然有 user 字段，但是值为空。
{ "user" : [null] } 虽然有 user 字段，但是值为空。
{ "foo" : "bar" } 没有 user 字段。
"""




"""   ----------------------------------------------- 查询的查询性能也不是很高
prefix 查询用于查询某个字段中以给定前缀开始的文档

查询 description 字段中包含有以 win 为前缀的关键词
GET books/_search
{
	"query": {
		"prefix": {
			"description": "win"
		}
	}
}



wildcard 查询    支持单字符通配符和多字符通配符
? 用来匹配一个任意字符，* 用来匹配零个或者多个字符
GET books/_search
{
  "query": {
    "wildcard": {
      "author": "李永*"
    }
  }
}



regexp query
匹配以 W 开头紧跟着数字的邮政编码
GET books/_search
{
	"query": {
		"regexp": {
			"postcode": "W[0-9].+"
		}
	}
}
"""


"""
        fuzzy query  模糊查询
用户在输入查询关键词时不小心把 “javascript” 拼成 “javascritp”，
在存在拼写错误的情况下使用模糊查询仍然可以搜索到含有 “javascript” 的文档        

GET books/_search
{
	"query": {
		"fuzzy": {
			"title": "javascritp"
		}
	}
}



type query 用于查询具有指定类型的文档
    查询 Elasticsearch 中 type 为 computer 的文档
GET books/_search
{
	"query": {
		"type": {
			"value": "computer"
		}
	}
}

"""



# ---------------------------------复合查询---------------------------------
""" bool 查询可
可以把任意多个简单查询组合在一起，使用 must、should、must_not、filter 选项来表示简单查询之间的逻辑，
每个选项都可以出现 0 次到多次
must 文档必须匹配 must 选项下的查询条件，相当于逻辑运算的 AND，且参与文档相关度的评分。
should 文档可以匹配 should 选项下的查询条件也可以不匹配，相当于逻辑运算的 OR，且参与文档相关度的评分。
must_not 与 must 相反，匹配该选项下的查询条件的文档不会被返回；需要注意的是，must_not 语句不会影响评分，它的作用只是将不相关的文档排除。
filter 和 must 一样，匹配 filter 选项下的查询条件的文档才会被返回，但是 filter 不评分，只起到过滤功能，与 must_not 相反。


查询 title 中包含关键词 java，并且 price 不能高于 70，description 可以包含也可以不包含虚拟机的书籍
GET books/_search
{
  "query": {
    "bool": {
      "filter": {
        "term": {
          "status": 1
        }
      },
      "must_not": {
        "range": {
          "price": {
            "gte": 70
          }
        }
      },
      "must": {
        "match": {
          "title": "java"
        }
      },
      "should": [
        {
          "match": {
            "description": "虚拟机"
          }
        }
      ],
      "minimum_should_match": 1
    }
  }
}


  dis_max查询  分离最大化查询
将任何与任一查询匹配的文档作为结果返回，但只将最佳匹配的评分作为查询的评分结果返回 


------------对比-----bool-------dis_max查询-------------------------

{
    "query": {
        "bool": {
            "should": [
                { "match": { "title": "Brown fox" }},
                { "match": { "body":  "Brown fox" }}
            ]
        }
    }
}


{ -----------------------------> 结果
  "hits": [
     {
        "_id":      "1",
        "_score":   0.14809652,
        "_source": {
           "title": "Quick brown rabbits",
           "body":  "Brown rabbits are commonly seen."
        }
     },
     {
        "_id":      "2",
        "_score":   0.09256032,
        "_source": {
           "title": "Keeping pets healthy",
           "body":  "My quick brown fox eats rabbits on a regular basis."
        }
     }
  ]
}
-----------------------------> 解释
因为 bool 匹配时 ，id=1 的匹配到了2条，但是 id = 2 的只匹配到了1条，尽管它有一条最佳匹配



{
    "query": {
        "dis_max": {
            "queries": [
                { "match": { "title": "Brown fox" }},
                { "match": { "body":  "Brown fox" }}
            ]
        }
    }
}

{    -----------------------------> 结果
  "hits": [
     {
        "_id":      "2",
        "_score":   0.21509302,
        "_source": {
           "title": "Keeping pets healthy",
           "body":  "My quick brown fox eats rabbits on a regular basis."
        }
     },
     {
        "_id":      "1",
        "_score":   0.12713557,
        "_source": {
           "title": "Quick brown rabbits",
           "body":  "Brown rabbits are commonly seen."
        }
     }
  ]
}


"""

"""  boosting query
用于需要对两个查询的评分进行调整的场景，boosting 查询会把两个查询封装在一起并降低其中一个查询的评分
positive 中的查询评分保持不变，
negative 中的查询会降低文档评分，
negative_boost 指明 negative 中降低的权值
GET books/_search
{
	"query": {
		"boosting": {
			"positive": {
				"match": {
					"title": "python"
				}
			},
			"negative": {
				"range": {
					"publish_time": {
						"lte": "2015-01-01"
					}
				}
			},
			"negative_boost": 0.2    ---------- 得分是原来的0.2倍
		}
	}
}
"""

# function_score query 可以修改查询的文档得分，这个查询在有些情况下非常有用，
# 比如通过评分函数计算文档得分代价较高，可以改用过滤器加自定义评分函数的方式来取代传统的评分方式。


"""
indices query 适用于需要在多个索引之间进行查询的场景


搜索索引 books、books2 中 title 字段包含关键字 javascript，其他索引中 title 字段包含 basketball 的文档
GET books/_search
{
	"query": {
		"indices": {
			"indices": ["books", "books2"],
			"query": {
				"match": {
					"title": "javascript"
				}
			},
			"no_match_query": {
				"term": {
					"title": "basketball"
				}
			}
		}
	}
}
"""



# ---------------------------------嵌套查询---------------------------------

# 在 Elasticsearch 这样的分布式系统中执行全 SQL 风格的连接查询代价昂贵，是不可行的。
# 相应地，为了实现水平规模地扩展，Elasticsearch 提供了以下两种形式的 join：

 

# nested query（嵌套查询）
#   文档中可能包含嵌套类型的字段，这些字段用来索引一些数组对象，每个对象都可以作为一条独立的文档被查询出来。

# has_child query（有子查询）和 has_parent query（有父查询）
#   父子关系可以存在单个的索引的两个类型的文档之间。has_child 查询将返回其子文档能满足特定查询的父文档，
#   而 has_parent 则返回其父文档能满足特定查询的子文档。

"""  定义 员工和 城市建的关系 ，也是父子关系

POST company/branch/_bulk
{ "index": { "_id": "london" }}
{ "name": "London Westminster","city": "London","country": "UK" }

POST company/employee/_bulk
{ "index": { "_id": 1,"parent":"london" }}
{ "name": "Alice Smith","dob": "1970-10-24","hobby": "hiking" }


PUT /company
{
	"mappings": {
		"branch": {},
		"employee": {
			"parent": { "type": "branch" }
		}
	}
}


搜索 1980 年以后出生的员工所在的分支机构，
employee 中 1980 年以后出生的有 Mark Thomas 和 Adrien Grand，他们分别在 london 和 paris，
GET company/branch/_search
{
	"query": {
		"has_child": {
			"type": "employee",
			"query": {
				"range": { "dob": { "gte": "1980-01-01" } }
			}
		}
	}
}



哪些机构中有名为 “Alice Smith” 的员工，因为使用 match 查询，
会解析为 “Alice” 和 “Smith”，所以 Alice Smith 和 Barry Smith 所在的机构会被匹配
GET company/branch/_search
{
	"query": {
		"has_child": {
			"type": "employee",
			"score_mode": "max",
			"query": {
				"match": { "name": "Alice Smith" }
			}
		}
	}
}




使用 min_children 指定子文档的最小个数。例如，搜索最少含有两个 employee 的机构
GET company/branch/_search?pretty
{
	"query": {
		"has_child": {
			"type": "employee",
			"min_children": 2,
			"query": {
				"match_all": {}
			}
		}
	}
}



has_parent query
搜索哪些 employee 工作在 UK
GET company/employee/_search
{
	"query": {
		"has_parent": {
			"parent_type": "branch",
			"query": {
				"match": { "country": "UK }
			}
		}
	}
}
"""